package org.rainbowinverted.charging.device.connect.ykc.server.decoder;

import cn.hutool.core.util.HexUtil;
import org.rainbowinverted.charging.device.api.operation.constants.DeviceOpConstantEnum;
import org.rainbowinverted.charging.device.connect.ykc.server.handler.YkcAbstractHandler;
import org.rainbowinverted.charging.device.connect.ykc.server.message.in.YkcMessageIn;
import org.rainbowinverted.charging.device.connect.ykc.server.message.out.YkcMessageOut;
import org.rainbowinverted.charging.device.connect.ykc.server.util.YkcOpCodeHandlerMap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

/**
 * 云快充解码器
 *
 * @author hehuaiping
 */
@Slf4j
@Component
@AllArgsConstructor
@ChannelHandler.Sharable
public class YkcDecoder extends MessageToMessageDecoder<ByteBuf> {
    private final YkcOpCodeHandlerMap ykcOpCodeHandlerMap;

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        int readableLength = byteBuf.readableBytes();
        byte[] dataBytes = new byte[readableLength];
        byteBuf.readBytes(dataBytes);
        String dataHex = HexUtil.encodeHexStr(dataBytes);
        byteBuf.resetReaderIndex();
        // 起始标志
        byte frameStartFlag = byteBuf.readByte();
        if (frameStartFlag != 0x68) {
            log.error("receive error data package: {}", dataHex);
            return;
        }
        // 数据长度
        int dataLength = byteBuf.readUnsignedByte();
        // 帧序列号
        Short frameSerialNo = byteBuf.readShortLE();
        // 加密标志
        Boolean cryptoFlag = byteBuf.readByte() == 0x00;
        // 帧类型标志
        Short frameType = byteBuf.readUnsignedByte();
        String frameTypeHex = String.format("%02x", frameType);
        log.info("receive frameSeq: {}, frameType: {}, data hex: {}", frameSerialNo, frameTypeHex, dataHex);
        // 消息体
        ByteBuf messageBody = byteBuf.copy(byteBuf.readerIndex(), byteBuf.readableBytes());
        Integer platformOpCode = ykcOpCodeHandlerMap.convertToPlatformCode(frameType.intValue());
        // 帧类型处理器
        YkcAbstractHandler<?, YkcMessageOut> handler = ykcOpCodeHandlerMap.getHandler(platformOpCode);
        if (Objects.isNull(handler)) {
            log.error("no handler for frameType: {}", frameTypeHex);
            return;
        }
        try {
            handler.read(channelHandlerContext, new YkcMessageIn(frameSerialNo.intValue(), frameType.intValue(), messageBody));
        } finally {
            messageBody.release();
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 处理设备离线
        ykcOpCodeHandlerMap.getHandler(DeviceOpConstantEnum.DISCONNECT.getOpCode()).read(ctx, null);
        super.channelUnregistered(ctx);
    }
}
